﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Xml;
using System.Net;
using System.IO;
using System.Text;
using System.Configuration;
using System.Runtime.Caching;
using NLog;

namespace Gollie.Payment.Targetpay
{
	public abstract class IDeal
	{
		protected static Logger logger = LogManager.GetCurrentClassLogger();

		protected MemoryCache MemCache = MemoryCache.Default;

		private bool testMode = false;

		protected bool error = false;
		private string errorMessage = "";

		public static string partnerId = "57429"; //targetpay

		protected readonly string banksUrl = "https://www.targetpay.com/ideal/getissuers.php?format=xml";
		protected readonly string checkUrl = "https://www.targetpay.com/ideal/check";
		protected readonly string fetchUrl = "https://www.targetpay.com/ideal/start";

		//BankWire
		protected readonly string kenmerkUrl = "https://www.targetpay.com/bankwire/start";

		public IDeal()
		{
		}

		public IDeal(bool testMode)
		{
			this.testMode = false;
		}

		protected virtual void ProcessTargetPayResponse(string response)
		{
			throw new NotImplementedException("ProcessTargetPayResponse");
		}

		protected void ProcessRequest(string url)
		{
			this.ProcessRequest(url, null);
		}

		private void SimulateProcessRequest(string url, Dictionary<string, string> args)
		{
			if (url == this.fetchUrl)
			{
				DateTime now = DateTime.Now;

				string trx = now.Year.ToString() + now.Month.ToString("00") + now.Day.ToString("00") + now.Hour.ToString("00") + now.Minute.ToString("00") + now.Second.ToString("00") + (now.Millisecond / 10).ToString("00");
				string response = "000000 " + trx + "|" + ConfigAppSettings.GetValue("idealsimulatorbankurl") + "?trxid=" + trx;
				this.ProcessTargetPayResponse(response);

				return;
			}

			if (url == this.checkUrl)
			{
				string response = "000000 OK";
				//string response = "TP0011 Transaction has been cancelled";
				this.ProcessTargetPayResponse(response);

				return;
			}

			if (url == this.kenmerkUrl)
			{
				DateTime now = DateTime.Now;

				string trx = now.Year.ToString() + now.Month.ToString("00") + now.Day.ToString("00") + now.Hour.ToString("00") + now.Minute.ToString("00") + now.Second.ToString("00") + (now.Millisecond / 10).ToString("00");
				string response = "000000 " + trx + "|83.53.14.014|NL49ABNA0835314014|ABNNOGWAT|St.Derdengelden TargetMedia|Rabobank";
				this.ProcessTargetPayResponse(response);

				return;

			}

			this.ProcessUri(url, args);
		}

		private void ProcessUri(string url, Dictionary<string, string> args)
		{
			try
			{
				if (args != null)
				{
					var uriBuilder = new UriBuilder(url);
					var query = HttpUtility.ParseQueryString(uriBuilder.Query);

					foreach (KeyValuePair<string, string> kvp in args)
					{
						if (string.IsNullOrEmpty(kvp.Value) == false)
							query[kvp.Key] = kvp.Value;
					}

					uriBuilder.Query = query.ToString(); //escaping is done automatically

					url = uriBuilder.ToString();
				}

				logger.Debug("Calling {0}", url);
				string response = WebReader.ReadUrl(url);
				this.ProcessTargetPayResponse(response);
			}
			catch (Exception e)
			{
				this.error = true;

				this.errorMessage = e.Message;

				logger.FatalException("IDeal/Bankwire processing exception: ", e);
			}
		}

		protected void ProcessRequest(string url, Dictionary<string, string> args)
		{
			if (Convert.ToBoolean(ConfigAppSettings.GetValue("simulatepayment")))
			{
				this.SimulateProcessRequest(url, args);
				return;
			}

			this.ProcessUri(url, args);
		}

		protected void LogReturnCode(string returnCode)
		{
			switch (returnCode)
			{
				case "TP0001": logger.Error("No layoutcode"); break;
				case "TP0002": logger.Error("Amount too low (0,84)"); break;
				case "TP0003": logger.Error("Amount too high (10.000,00"); break;
				case "TP0004": logger.Error("No or invalid return url"); break;
				case "TP0005": logger.Error("No bank ID"); break;
				case "TP0006": logger.Error("No description"); break;
				case "TP0009": logger.Error("Invalid or no user ip given"); break;
				case "TP0010": logger.Error("Transaction in progress...please try again"); break;
				case "TP0011": logger.Error("Transaction cancelled"); break;
				case "TP0012": logger.Error("Transaction expired"); break;
				case "TP0013": logger.Error("Transaction could not be handled"); break;
				case "TP0014": logger.Error("Transaction already handled"); break;
				case "TP0016": logger.Error("No iDeal approval for this account yet"); break;
				case "TP0017": logger.Error("Incorrect rtlo code"); break;
				case "TP0019": logger.Error("Account disabled"); break;
				case "TP0020": logger.Error("Missing layoutcode"); break;
				case "TP0021": logger.Error("Missing transactionID"); break;
				case "TP0022": logger.Error("Transaction not found"); break;
				case "TP0023": logger.Error("Layoutcode doesn't match tranactionID"); break;
				case "TP9997": logger.Error("Internal error, failed to create transaction (maintenance)"); break;
				case "TP9998": logger.Error("Failed to create transaction"); break;
				case "TP9999": logger.Error("Your account has been blocked"); break;
				case "SO1000": logger.Error("Storing in systeem"); break;
				case "SO1200": logger.Error("Systeem te druk. Probeer het later nog eens"); break;
				case "SO1400": logger.Error("Onbeschikbaar door onderhoudswerkzaamheden"); break;
				default: logger.Error("Unknown returncode: " + returnCode); break;
			}
		}

		protected void ThrowXmlException(XmlDocument doc)
		{
			throw new XmlException(doc.InnerXml);
		}

		public bool TestMode
		{
			get { return this.testMode; }
			set { this.testMode = value; }
		}

		public bool Error
		{
			get { return this.error; }
		}

		public string ErrorMessage
		{
			get { return this.errorMessage; }
		}
	}
}